<template>
  <!-- #TODO: @pablo 有几个问题：
        1、 这个组件其实并不属于在router里面定义了，需要单独显示的一个page/view，它本身是作为一个component嵌入到某一个page/view中显示的，这种情况，不应该放在这个目录下，应该放到components目录下。此目录下的ImgSend,GuidRequest,PageChatList,PageGuideList,PageMap,VoiceSend等都是一样的
        2、 模板缩进有问题，有多余空格、空行的情况，用prettier或者formatter调一下缩进。如果缩进不对的话，容易出bug，也没有达到html语义化的作用；
        3、 tag的名字，可以参考 https://cn.vuejs.org/v2/style-guide/index.html#模板中的组件名大小写-强烈推荐 这个链接里面的，使用 PascalCase的方式，即 <QList> 变为 <QList>，下同；
  -->
  <QList class="no-border groupOnLine">
    <QListHeader>在线操作员</QListHeader>
    <QCollapsible icon="perm_identity" label="在线人员">
      <QItem v-for="person in personList" :key="person.userID" class="item">
        <img class="q-mx-sm" src="../assets/image/member.png">
        <QItemMain class="text-white">
          {{person.userName}}
          <QTooltip @mmmm="handler($event)">
            <QList class="no-border">
              <q-item>姓名：{{person.fullName}}</q-item>
              <q-item>编号：{{person.userID}}</q-item>
              <q-item>官阶：{{person.userName}}</q-item>
            </QList>
          </QTooltip>
          <!-- #TODO: @pablo 一般情况下，html tag的闭合范围内如果有内容，应该使用<div>xxxxx</div>的双闭合tag，如果闭合范围内没有内容，则使用自闭合tag：<div class="xxx" />.
                  下一行这种情况就应该使用 <QChip floating ... /> 这种自闭合tag；
                  参考自闭合组件说明： https://cn.vuejs.org/v2/style-guide/index.html#自闭合组件-强烈推荐
          -->
          <q-chip
            floating
            color="red"
            v-show="getLength(person.userID, 1) !== 0"
            v-html="getLength(person.userID,1)"
          />
        </QItemMain>
        <q-item-side
          right
          icon="chat_bubble"
          @click.native="getChatMagCurrentPorG(person.userID,1),setUserName(person.userName),clearNewMsgSign(person.userID,1)"
        ></q-item-side>
      </QItem>
    </QCollapsible>
    <!-- #TODO: @pable 这三个<QCollapsible />组件中包含的模板其实是一样的，只是数据不一样而已，一般这种情况下，就要考虑单独抽出来一个组件了。像这里，新抽出来一个组件，在props里面定义一个输入属性，把数据传进去就好了；
    这一点很重要，不断抽象，把自己的组件变小，功能变单一、普适性更强，对你的程序思维会很有帮助-->
    <q-collapsible v-for="group in groups" :key="group.groupID">
      <template slot="header">
        <q-item-side left>
          <q-icon name="perm_identity"/>
        </q-item-side>
        <q-item-main :label="group.groupName">
          <q-chip
            floating
            color="red"
            v-show="getLength(group.groupID, 2) !== 0"
            v-html="getLength(group.groupID,2)"
          />
        </q-item-main>
        <q-item-side right>
          <q-icon
            name="chat_bubble"
            color="red"
            size="24px"
            @click.native.stop="getChatMagCurrentPorG(group.groupID,2), setUserName(group.groupName),clearNewMsgSign(group.groupID,2)"
          />
        </q-item-side>
      </template>

      <q-item v-for="person in group.groupUsers" :key="person.userID" class="item">
        <img class="q-mx-sm" src="../assets/image/member.png">
        <q-item-main class="text-white">
          {{person.userName}}
          <q-tooltip>
            <q-list class="no-border">
              <q-item>姓名：{{person.fullName}}</q-item>
              <q-item>编号：{{person.userID}}</q-item>
              <q-item>官阶：{{person.userName}}</q-item>
            </q-list>
          </q-tooltip>
          <q-chip
            floating
            color="red"
            v-show="getLength(person.userID, 1) !== 0"
            v-html="getLength(person.userID,1)"
          />
        </q-item-main>
        <q-item-side
          right
          icon="chat_bubble"
          @click.native.stop="getChatMagCurrentPorG(person.userID,1),setUserName(person.userName),clearNewMsgSign(person.userID,1)"
        ></q-item-side>
      </q-item>
    </q-collapsible>
    <!-- #TODO: @Pablo 一个小建议，关于变量命名的，这里的v-model 传进去的是一个Boolean类型的，那么在变量命名的时候就要体现出来，比如isOpened, openState这种会比opened更具有直观意义；
    像你上两行的@click.native.stop的事件处理handler，以动词set，get，clear开头，就很直观；其他的命名也请参考-->
    <q-modal v-model="isOpened">
      <q-modal-layout>
        <q-toolbar slot="header" class="header">
          <q-toolbar-title>{{userName}}</q-toolbar-title>
          <q-toolbar-title>chatPanel</q-toolbar-title>
          <!-- #TODO: @Pablo QBtn组件这种每一个attrs一行的格式和你前面组件的格式有冲突，请统一，89行的QInpput也是类似， QChatMessage等也都要注意修改 -->
          <q-btn flat round dense v-close-overlay icon="keyboard_arrow_left"/>
        </q-toolbar>
        <q-toolbar slot="footer" class="footer">
          <div class="column full-width">
            <div class="row items-center justify-around full-width">
              <sendImg :jsonPkg="jsnPkgMsgSend" :lastDialogID="lastDialogID"></sendImg>
              <img src="../assets/image/textMsgIcon.png">
              <sendVoice :jsonPkg1="jsnPkgMsgSend" :lastDialogID="lastDialogID"></sendVoice>
            </div>
            <!-- #TODO: @Pablo 使用float-label, place-holder等交互组件时，一定要注意修改默认的label和holder, 这种比较细节，但是比较显功力 -->
            <q-input
              v-model="area"
              type="textarea"
              float-label="Textarea"
              :max-height="100"
              rows="3"
              :after="[
                      {
                        icon: 'send',
                        content: true,
                        handler () {
                          // do something...
                          sendTextMsg()
                        }
                      }
                    ]"
              class="inputBox"
            />
          </div>
        </q-toolbar>
        <div class="q-pa-md">
          <div v-for="msg in chatMsgCurrentPartner" :key="msg.dialogID">
            <!-- <template v-if="confirmMe(msg.userID)"> -->
            <template v-if="msg.contentType === '1'">
              <q-chat-message
                :name="msg.senderID == String(userID) ? 'me' : msg.senderName"
                :text="[msg.textMsg]"
                :stamp="msg.timeStamp"
                avatar="../assets/image/head.png"
                :sent="msg.senderID === String(userID)"
              />
            </template>
            <template v-if="Number(msg.contentType) > 1 ">
              <q-chat-message
                :name="msg.senderID === String(userID) ? 'me' : msg.senderName"
                :stamp="msg.timeStamp"
                avatar="../assets/image/head.png"
                :sent="msg.senderID === String(userID)"
              >
                <img
                  :src="msg.contentType === '2' ? '../assets/voice_icon_left.png' : msg.src"
                  :alt="msg.contentType === '2' ? 'voice' : 'img'"
                  :class="msg.contentType === '2' ? '' : 'imgClickDisplay displayImg'"
                  @click.stop="() => {msg.contentType === '2' ? playVoice(msg.dialogID) : setImgClickDispaly($event)} "
                >
                <audio v-if="msg.contentType === '2'" :src="msg.src" :ref="msg.dialogID"/>
              </q-chat-message>
            </template>
          </div>
        </div>
      </q-modal-layout>
    </q-modal>
    <q-modal class="maximized" v-model="imgClickOpened">
      <q-modal-layout>
        <img class="largeSizeImg" :src="imgSrc" alt="点击放大图像">
        <q-btn color="primary" @click="imgClickOpened = false" label="Close"/>
      </q-modal-layout>
    </q-modal>
  </QList>
</template>

<script>
import Vue from 'vue'
import drag from 'v-drag'
import sendImg from './ImgSend'
import sendVoice from './VoiceSend'
import ConstUrl from '../const.json'

Vue.use(drag)

export default {
  components: { sendImg, sendVoice },
  data () {
    return {
      userID: '',
      userName: '',
      personList: [], /* #TODO: @pablo 看这个命名应该是个数组，那么初始化的时候，应该要为[]或者初始数据类型，一定要让别人从变量命名就能明白这个变量的类型和用处  */
      area: '',
      imgContentType: 3,
      voiceContentType: 2,
      jsnPkgUserOnline: {
        commonKey: 100,
        appKey: 1,
        userID: this.$q.cookies.get('userID'),
        data: {}
      },
      jsnPkgUsersInGroup: {
        commonKey: 403,
        appKey: 11,
        userID: this.$q.cookies.get('userID'),
        data: {}
      },
      jsnPkgChatMsgAllGet: {
        commonKey: 100,
        appKey: 3,
        userID: this.$q.cookies.get('userID'),
        data: {
          lastDialogID: 0,
          senderID: this.$q.cookies.get('userID')
        }
      },
      jsnPkgChatMsgSingleInit: {
        commonKey: 100,
        appKey: 6,
        userID: this.$q.cookies.get('userID'),
        data: {
          userID: this.$q.cookies.get('userID'),
          partnerID: '',
          // msgType: 1 || 2,
          msgType: 1,
          msgCount: 50
        }
      },
      jsnPkgChatMsgSingleUpdata: {
        commonKey: 100,
        appKey: 7,
        userID: this.$q.cookies.get('userID'),
        data: {
          userID: this.$q.cookies.get('userID'),
          partnerID: '',
          msgType: '',
          lastDialogID: ''
        }
      },
      jsnPkgMsgSend: {
        commonKey: 100,
        appKey: 4,
        userID: this.$q.cookies.get('userID'),
        data: {
          userID: this.$q.cookies.get('userID'),
          senderID: this.$q.cookies.get('userID'),
          groupID: '',
          msgType: '',
          receiverID: '',
          lastDialogID: '',
          textMsg: '',
          contentType: ''
        }
      },
      groups: null,
      open: false,
      isOpened: false,
      data: {
        partnerID: '',
        msgType: '',
        lastDialogID: ''
      },
      chatMsgCurrentPartner: [],
      lastDialogID: '',
      lastDialogIDTotal: '',
      newMsg: [],
      imgClickOpened: false,
      imgSrc: '',
      timerUpdataMsgTotal: 0,
      timerUpdataChatMsg: 0
    }
  },
  methods: {
    confirmMe (userID) {
      /* #TODO: @pablo 这里写法有问题，
      一个很简单的改法是： return userID === this.userID, 简单明了；
      如果你的逻辑分支返回的是非boolean变量： if (x) return A else return B的情况，考虑使用三元运算符： return x ? A : B。
      一行代码能轻松优雅的解决
      */
      return userID === this.userID
    },
    async getOnlineUser () {
      /** #TODO pablo ,have to confirm the res is the data needed later */
      const res = await this.httpPost(this.jsnPkgUserOnline)
      this.personList = res
      if (this.$q.cookies.get('userID')) setTimeout(this.getOnlineUser, 2000)
    },
    async getOnlineGroup () {
      //   this.getData(this.gjsnData)
      const res = await this.httpPost(this.jsnPkgUsersInGroup)
      this.groups = res
      if (this.$q.cookies.get('userID')) setTimeout(this.getOnlineGroup, 2000)
    },
    async getChatMagCurrentPorG (partnerID, msgType) {
      this.isOpened = true
      /* set jsnPkgMsgSend , jsnPkgMsgSend is userd in the q-modal ,so it has to be set here */
      this.jsnPkgMsgSend.data.receiverID = partnerID
      this.jsnPkgMsgSend.data.msgType = msgType
      this.jsnPkgMsgSend.data.groupID =
        this.jsnPkgMsgSend.data.msgType === 2 ? partnerID : ''
      // set initChatMsg partnerID msgType
      /* jsonPkg.data = {...partnerID, msgType, userID: this.$q.cookies.get('userID')} */
      //   let [jsonPkg.data.partnerID, jsonPkg.data.msgType, jsonPkg.data.userID] = [partnerID, msgType, this.$q.cookies.get('userID')]
      this.jsnPkgChatMsgSingleInit.data.partnerID = partnerID
      this.jsnPkgChatMsgSingleInit.data.msgType = msgType
      this.jsnPkgChatMsgSingleInit.data.userID = this.$q.cookies.get('userID')

      this.jsnPkgChatMsgSingleUpdata.data.msgType = msgType
      this.jsnPkgChatMsgSingleUpdata.data.partnerID = partnerID
      /* #TODO is this avilable ?const {data} = await this.httpPost(jsonPkg) or in which way the await can return the data? */
      const res = await this.httpPost(this.jsnPkgChatMsgSingleInit)
      /** need to comfirm the res exit if res ===unfined or '' wherther set lastDialogID here should think about */
      /** set img and audio contentType the url that can fetch it and set the chat message rendered */
      this.chatMsgCurrentPartner = this.setSrc(res)
      // this.timerUpdataChatMsg = setInterval(this.updateCurrentMsg, 2000)
      this.updateCurrentMsg()
    },
    async updateCurrentMsg () {
      /** set jsnPkgChatMsgSingleUpdata */
      const lastDialogID = this.chatMsgCurrentPartner.length === 0 ? 0 : this.chatMsgCurrentPartner[this.chatMsgCurrentPartner.length - 1].dialogID
      /** set jsnPkgMsgSend's lastDialogID */
      this.jsnPkgMsgSend.data.lastDialogID = lastDialogID

      /* #TODO @pablo 对象赋值、merge请参考以下代码
        const userID =  this.$q.cookies.get('userID')
        const addData = {
          data: {lastDialogID, userID},
          userID
        }
        Object.assign(this.jsnPkgChatMsgSingleUpdata, addData)
      */

      this.jsnPkgChatMsgSingleUpdata.data.lastDialogID = lastDialogID
      this.jsnPkgChatMsgSingleUpdata.data.userID = this.$q.cookies.get('userID')
      this.jsnPkgChatMsgSingleUpdata.userID = this.$q.cookies.get('userID')
      /** post data */
      const res = await this.httpPost(this.jsnPkgChatMsgSingleUpdata)
      if (res.length > 0) this.chatMsgCurrentPartner = this.chatMsgCurrentPartner.concat(this.setSrc(res))
      if (this.isOpened) setTimeout(this.updateCurrentMsg, 2000)
      // this.chatMsgCurrentPartner = res.length === 0 ? this.chatMsgCurrentPartner : this.chatMsgCurrentPartner.concat(this.setSrc(res))
    },
    // updateMsg () {
    //   /* #TODO: @pablo 在组件中使用setInterval一定要特别注意！！ 一般做法是， 定义一个ViewModel来接这个timer，比如this.timer=setInterval(xxx), 在beforeDestory的钩子里面里面销毁timer，clearInterval(this.timer)， this.timer = null */
    //   this.timerUpdataChatMsg = setInterval(this.getData, 2000, this.updataChatMsgPkg)
    // },
    async sendTextMsg () {
      /** set jsnPkgMsgSend when this function is userd */
      this.jsnPkgMsgSend.userID = this.$q.cookies.get('userID')
      this.jsnPkgMsgSend.senderID = this.$q.cookies.get('userID') /** this may not be necessary */
      this.jsnPkgMsgSend.data.contentType = 1
      this.jsnPkgMsgSend.data.textMsg = this.area
      const res = await this.httpPost(this.jsnPkgMsgSend)
      this.area = ''
      console.log('sendText success', res)
    },
    setUserName (userName) {
      this.userName = userName
    },
    setSrc (messages) {
      // const url = window.location.host
      /* # TODO:: @pablo 这个遍历写的很业余啊，请用ES6语法forEach,map,every等改写 */
      messages.map(message => {
        /** #TODO 这里的url要修改为window.location.host */
        message.src = message.contentType === '2' || message.contentType === '3' ? `http://test2.goolton.com/getDialogFile.php?dID=${message.dialogID}` : undefined
        message.contentType === '2' ? (message.srcVoiceImg = message.partnerID === message.senderID ? '../assets/voice_icon_right.png' : '../assets/voice_icon_left.png') : message.srcVoiceImg = undefined
      })
      /* #TODO: @pablo if分支写的很混乱，参考getData()的review意见，把if里的condition分开，理清楚逻辑 */
      /* #TODO: @pablo 使用三元运算符 */
      return messages
    },
    playVoice (dom) {
      /* #TODO: @pablo 1、变量命名不要用a！！！ 2、变量a后续没有重新赋值和改写，请使用const代替let */
      const audioPlay = this.$refs[dom][0]
      audioPlay.play()
    },
    setImgClickDispaly (e) {
      this.imgClickOpened = true
      this.imgSrc = e.target.src
    },
    async httpPost (pkg) {
      const params = new FormData()
      params.append('gdData', JSON.stringify(pkg))
      const { data: { data } } = await this.$http({
        url: ConstUrl.url,
        method: 'post',
        data: params,
        headers: {
          Accept: '*/*',
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
          'X-Requested-With': 'XMLHttpRequest'
        }
      })
      return data
    },
    async initLastDialogIDTotal (pkg) {
      /* #TODO: @pablo 这应该是一个异步操作，那你要确认一下，主函数initLastDialogIDTotal和你的异步操作是否有必要同步，这种时候有可能会出bug的，请确认，最好还是用async/await */
      const data = await this.httpPost(pkg)
      console.log(`this: ${this}`) // need to be clear about where this refer to
      // me.getAllMsg.data.lastDialogID = data[data.length - 1].dialogID
      return data.length > 0 ? data[data.length - 1].dialogID : 0
    },

    async updateMsgTotal (pkg) {
      const me = this /* #TODO: @pablo 在下面异步操作里面用的是箭头函数，那么可以直接用this,建议使用async/await */
      let data = await me.httpPost(pkg)
      if (data.length !== 0) {
        me.jsnPkgChatMsgAllGet.data.lastDialogID = data[data.length - 1].dialogID
        // clear the msg in groupMsg where senderID = myself
        data = data.filter(item => item.senderID !== `${me.$q.cookies.get('userID')}`)
        me.newMsg = me.newMsg.concat(data)
      }
    },
    async initAndUpdateMsgTotal () {
      const pkg = this.jsnPkgChatMsgAllGet
      /** pkg's LastDialogID=0 */
      const dialogID = await this.initLastDialogIDTotal(pkg)
      /** set jsonPkg init lastDIalogID */
      this.jsnPkgChatMsgAllGet.data.lastDialogID = dialogID
      /** set timer after init lastdialogID */
      this.timerUpdataMsgTotal = setInterval(this.updateMsgTotal, 2000, pkg)
    },
    getLength (id, msgType) {
      /* #TODO: @pablo 改为 ？ ： 三元运算符的格式 */
      /** the senderID of a groupMsg and a person msg will both be the same */
      return msgType === 2 ? this.newMsg.filter(data => data.groupID === id).length : this.newMsg.filter(data => Number(data.msgType) !== 2 && data.senderID === id).length
    },
    chipDisplay (id, msgType) {
      /* #TODO: @pablo
      1、不要用a！
      2、这里是不是可以直接考虑写在模板里面？用声明式的写法 <div :attr="getLength(id, msgType) !== 0 " />
      */
      return this.getLength(id, msgType) !== 0
    },
    clearNewMsgSign (id, msgType) {
      /* #TODO: @pablo 应该是可以写到模板里面的，参考chipDisplay() review意见  */
      if (this.newMsg !== 0) {
        this.newMsg = msgType === 2 ? this.newMsg.filter(msg => msg.groupID !== id) : this.newMsg = this.newMsg.filter(msg => msg.senderID !== id)
      }
    }
  },
  created () {
    this.userID = this.$q.cookies.get('userID')
  },
  /* #TODO: @pablo 这个生命周期的定义放到methods前面， 下同 */
  async mounted () {
    await this.getOnlineUser()
    await this.getOnlineGroup()
    await this.initAndUpdateMsgTotal()
  },
  beforeDestroy () {
    clearInterval(this.timerUpdataMsgTotal)
    clearInterval(this.timerUpdataChatMsg)
  }
}
</script>

<style lang="stylus">
@import ('~variables');

.q-modal-layout {
  width: 20vw;
  height: 60vh !important;
  background-color: $neutral;

  .q-message-avatar {
    width: 25px;
    height: 25px;
  }

  .q-message-sent {
    // background-color: $darkSlateGray;
  }

  .displayImg {
    width: 5vw;
    height: 10vh;
  }

  .inputBox {
    background-color: $darkSlateGray !important;
  }

  .header {
    background-color: $darkSlateGray !important;
  }

  .footer {
    padding: 0px;
    background-color: $mediumSpringGreen !important;
  }
}

.largeSizeImg {
  width: 50vw;
  height: 70vh;
}

.groupOnLine {
  overflow-y: auto;
  width: 100%;
  height: 100%;

  img.folder {
    width: 10px;
    height: 10px;
  }

  img {
    width: 30px;
    height: 30px;
  }

  // .online {
  // overflow-y: auto;
  // height: 10vh;
  // }
  .item {
    height: 10px;
  }

  .textBox {
    width: 100%;
    height: 100px;
  }

  .q-chip-floating {
    top: 0.1em;
    right: 21.7em;
  }
}
</style>
